package com.isasa.android.bluetoothpractice.service;

import android.app.Service;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.support.annotation.Nullable;

import com.isasa.android.bluetoothpractice.Rx.RxBle;
import com.isasa.android.bluetoothpractice.base.Action;
import com.isasa.android.bluetoothpractice.base.Category;
import com.isasa.android.bluetoothpractice.base.Command;
import com.isasa.android.bluetoothpractice.util.BleDataDeal;
import com.isasa.android.bluetoothpractice.util.SPUtils;

import rx.functions.Action1;

public class RxBleService extends Service {
    private RxBle mrxBle = RxBle.getInstance();
    private BleDataDeal bleDataDeal = new BleDataDeal();
    private String maddress;
    public boolean hereOver = false;
    //communication
    private BleDataDeal.OnReceivedOKListener monReceivedOKListener;
    private RxBleService.OnMessageReceiveListener monMessageReceiveListener;

    private boolean msendDataState;
    private RxBleServiceReceiver mreceiver = new RxBleServiceReceiver();
    private RxBle.BleScanListener mscanListener = new RxBle.BleScanListener() {
        @Override
        public void onBleScan(BluetoothDevice bleDevice, int rssi, byte[] scanRecord) {
            //LeScan have set default scanType to Le
            if (bleDevice.getBondState() != BluetoothDevice.BOND_BONDED && bleDevice.getBondState() != BluetoothDevice.BOND_BONDING) {
                if ((maddress!=null&&maddress.equals(bleDevice.getAddress())) || bleDevice.getName().contains("AeroBand") ) {
                    mrxBle.connectDevice(bleDevice);
                }
            }
        }
    };

    public RxBleService() {
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        maddress = SPUtils.getInstance().getString("ADDRESS","");

        return START_STICKY;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        initReceiver();
        readyBond();
    }


    @Override
    public void onDestroy() {
        terminateBle();
        terminateReceiver();
        super.onDestroy();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private void terminateBle() {
        if (mrxBle != null) {
            mrxBle.closeBle();
        }
    }

    private void terminateReceiver() {
        if (mreceiver != null) {
            unregisterReceiver(mreceiver);
        }
    }
    public void reScan(){
        if(mrxBle!=null){
            mrxBle.scanBleDevices(false);
            mrxBle.setScanListener(mscanListener);
            mrxBle.scanBleDevices(true);

        }
    }
    private void initReceiver() {
        IntentFilter filter = new IntentFilter();
        //TODO design compatible category
        filter.addCategory(Category.MUSIC_ACTIVITY);
        registerReceiver(mreceiver, filter);
    }


    public void readyBond() {
        //TODO permission manage

//        Intent requestBluetoothOn = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
//        requestBluetoothOn.setAction(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
//        requestBluetoothOn.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 250);
//        startActivity(requestBluetoothOn);
        //TODO state manage and distribute
        if (mrxBle != null) {
            mrxBle.openBle(this);
            mrxBle.setScanListener(mscanListener);
            mrxBle.scanBleDevices(true);

            hereOver = true;
        }
    }

    /**
     * default delay set to 0
     * @param command command provided in Command
     * @return sendData state on return
     */
    public boolean sendCommand(int command){
        return sendCommand(command,0);
    }

    /**
     * send command
     *
     * @param command constant in Command
     * @param delay  milliseconds
     * @return state success or not
     */
    public boolean sendCommand(int command, final int delay) {
        switch (command) {
            case Command.DEVICE_COMMAND_BEGIN_OPEN_MPU:
                if (mrxBle != null) {
                    msendDataState=mrxBle.sendData(BleDataDeal.sendCommand(0x01,Command.DEVICE_COMMAND_BEGIN,Command.DEVICE_COMMAND_BEGIN_OPEN_MPU), 0);
                }
                break;
            case Command.DEVICE_COMMAND_CHOOSE_INSTRUMENT_DRUM:
                        msendDataState=mrxBle.sendData(BleDataDeal.sendCommand(0x01,Command.DEVICE_COMMAND_CHOOSE_INSTRUMENT,Command.DEVICE_COMMAND_CHOOSE_INSTRUMENT_DRUM),delay);

                break;
            case Command.DEVICE_COMMAND_CLOSE:
                        msendDataState = mrxBle.sendData(BleDataDeal.sendCommand(0x01,Command.DEVICE_COMMAND_CLOSE),0);

                break;
            case Command.DEVICE_COMMAND_POWER_OFF:
                msendDataState = mrxBle.sendData(BleDataDeal.sendCommand(0x01,Command.DEVICE_COMMAND_POWER_OFF),0);
            default:
                msendDataState=false;
                break;
        }
        return msendDataState;
    }
    /**
     * Deal with data start if OnReceivedOkListener is set
     */
    public void dealWithData() {
        if (monReceivedOKListener != null) {
            mrxBle.receiveData().subscribe(new Action1<byte[]>() {
                @Override
                public void call(byte[] bytes) {
                    for (int i = 0; i < bytes.length; i++) {
                        if (bytes[i] < 0) {
                            bleDataDeal.receive(bytes[i] + 256);
                        } else {
                            bleDataDeal.receive(bytes[i]);
                        }
                    }
                }
            });
        }
    }

    /**
     * set callback to bluetooth scan, or apply default scan listener
     *
     * @param scanListener
     */
    public void setScanListener(RxBle.BleScanListener scanListener) {
        mscanListener = scanListener;
    }

    /**
     * have RxBleService convey data to this listener when reported OK.
     *
     * @param listener
     */
    public void setOnReceivedOKListener(BleDataDeal.OnReceivedOKListener listener) {
        monReceivedOKListener = listener;
        bleDataDeal.setOnReceivedOKListener(listener);
    }

    /**
     * have RxBle deal with inner logic
     */
    public void setOnMessageReceiveListener(OnMessageReceiveListener listener) {
        monMessageReceiveListener = listener;
    }

    public interface OnMessageReceiveListener {
        void onMessageReceived(int action, byte data[]);
    }

    private class RxBleServiceReceiver extends BroadcastReceiver {
        //TODO design inner receiver to broadcast
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            switch (action) {
                case Action.RXBLESERVICE_READYBOND:
                    readyBond();
                default:
                    break;
            }
        }
    }

    public static RxBleService getInstance() {
        return RxBleService.Singleton.INSTANCE;
    }

    private static class Singleton {
        private static final RxBleService INSTANCE = new RxBleService();
    }
}
